package su.jet.common.irc.protocol;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;

import su.jet.common.irc.domain.Message;
import su.jet.common.irc.protocol.request.Request;

//[DF] TODO: It is reasonable to name this class Session or Connection, not Protocol.
public class Session {

	private InputStream inputStream;
	private OutputStream outputStream;
	private Socket connection;
	
		
	public Session(Socket connection) throws IOException {
		this.connection = connection;
		this.inputStream = connection.getInputStream();
		this.outputStream = connection.getOutputStream();
	}

	public void sendRequest(Request request) throws IOException {
		this.sendObject(request);
	}
	
	public Request recieveRequest() throws IOException, ClassNotFoundException {
		Object recieveObj = this.recieveObject();
		if (recieveObj instanceof Request)
			return (Request)recieveObj;
		else
			return null;
	}
	
	public void sendAnswer(Answer answer) throws IOException {
		this.sendObject(answer);
	}
	
	public Answer recieveAnswer() throws IOException, ClassNotFoundException {
		//[ek] TODO dublicate code detected. Reuse it.
		Object recieveObj = this.recieveObject();
		if (recieveObj instanceof Answer)
			return (Answer)recieveObj;
		else
			return null;
	}
	
	public void sendMessage(Message message) throws IOException {
		this.sendObject(message);
	}
	
	public Message recieveMessage() throws IOException, ClassNotFoundException {
		Object recieveObj = this.recieveObject();
		if (recieveObj instanceof Message)
			return (Message)recieveObj;
		else
			return null;
	}
	
	public void sendObject(Object obj) throws IOException {
		BufferedOutputStream bos = new BufferedOutputStream(outputStream); //[ek] TODO why do this at _every_ method call?
		//[DF] TODO: Fully agree with ek. It will be better to instantiate OOS on top of BOS in constructor.
		ObjectOutputStream oos = new ObjectOutputStream(bos);
		oos.writeObject(obj);
		oos.flush();
	}
	
	public Object recieveObject() throws IOException, ClassNotFoundException {
		//[DF] TODO: Some as with sendObject
		BufferedInputStream bis = new BufferedInputStream(inputStream);
		ObjectInputStream ois = new ObjectInputStream(bis);
		return ois.readObject();
	}

	
	// [DF] FIXME: Dead code?
	
	
	//[DF] TODO: Go on and hide all connection related logic in this class. You should public only
	//session related methods for outer classes.
//	public Socket getConnection() {
//		return this.connection;
//	}
	
	public void disconnect() {
		try {
			connection.close();
		} catch (IOException e) {
			System.out.println("Error closing connection!");
			//e.printStackTrace();
		}
	}
}